/**
 * Created by Administrator on 14-3-25.
 */
define(function(require,exports,module){
	var jQuery=require('jquery');
	(function ($)
	{
		if (!document.defaultView || !document.defaultView.getComputedStyle)
		{ // IE6-IE8
			var oldCurCSS = $.curCSS;
			$.curCSS = function (elem, name, force)
			{
				if (name === 'background-position')
				{
					name = 'backgroundPosition';
				}
				if (name !== 'backgroundPosition' || !elem.currentStyle || elem.currentStyle[name])
				{
					return oldCurCSS.apply(this, arguments);
				}
				var style = elem.style;
				if (!force && style && style[name])
				{
					return style[name];
				}
				return oldCurCSS(elem, 'backgroundPositionX', force) + ' ' + oldCurCSS(elem, 'backgroundPositionY', force);
			};
		}

		var oldAnim = $.fn.animate;
		$.fn.animate = function (prop)
		{
			if ('background-position' in prop)
			{
				prop.backgroundPosition = prop['background-position'];
				delete prop['background-position'];
			}
			if ('backgroundPosition' in prop)
			{
				prop.backgroundPosition = '(' + prop.backgroundPosition;
			}
			return oldAnim.apply(this, arguments);
		};

		function toArray(strg)
		{
			strg = strg.replace(/left|top/g, '0px');
			strg = strg.replace(/right|bottom/g, '100%');
			strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g, "$1px$2");
			var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
			return [parseFloat(res[1], 10), res[2], parseFloat(res[3], 10), res[3]];
		}

		$.fx.step.backgroundPosition = function (fx)
		{
			if (!fx.bgPosReady)
			{
				var start = $.curCSS(fx.elem, 'backgroundPosition');
				if (!start)
				{//FF2 no inline-style fallback
					start = '0px 0px';
				}

				start = toArray(start);
				fx.start = [start[0], start[2]];
				var end = toArray(fx.end);
				fx.end = [end[0], end[2]];

				fx.unit = [end[1], end[3]];
				fx.bgPosReady = true;
			}
			//return;
			var nowPosX = [];
			nowPosX[0] = ((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0] + fx.unit[0];
			nowPosX[1] = ((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1] + fx.unit[1];
			fx.elem.style.backgroundPosition = nowPosX[0] + ' ' + nowPosX[1];

		};
	})(jQuery);



	/*
	 tlrkSlider

	 example usage:

	 $("#slider").tlrkSlider({
	 autoStart: false,
	 elements: {
	 "img": {delay: 10},
	 "h2": {delay: 500},
	 ".copy": {delay: 800},
	 ".button": {delay: 1000}
	 }
	 });

	 to go to a specific frame:
	 $("#slider").tlrkSlider("go", position);
	 "position" can have one of the following values:
	 "next", "prev", "first", "last", "+1", "-1" or a numeric value

	 to start/stop the automatic loop:
	 $("#slider").tlrkSlider("start");
	 $("#slider").tlrkSlider("stop");

	 to change the delay between automatic transitions:
	 $("#slider").tlrkSlider("option", "delayAnimation", 1000);

	 to change any option:
	 $("#slider").tlrkSlider("option", option_name, option_value);

	 Changing the "elements" object is not tested.

	 Changing the following options: "navigation", "navigationClass", "framesSelector", "autoStart" won't have any effect for now.
	 They are used only during the initialization.

	 $("#slider").data("tlrkSlider") will return the plugin instance and the methods/properties can be accessed from there.

	 The plugin contructor defaults are accessable through TlrkSlider.defaults

	 The function that actually sweep the elements in/out can be overriden from
	 TlrkSlider.prototype._animationIn and TlrkSlider.prototype._animationOut

	 See sweepIn/sweepOut

	 */



	;(function( $, window, document, undefined ){

		// utility function that generates the "dots" navigation
		function generateNavigation($el, count, config) {
			var i, html = "",
				width = count * 24;

			html += "<ol class='" + config.navigationClass + "' style='margin-left: -" + width/2 + "px; width: " + width + "px'>";
			for (i = 0; i < count; i++) {
				html += "<li><a " + (i === 0 ? "class='selected'" : "" ) + " href='#" + (i) + "'>slide</a></li>";
			}
			html += "</ol>";

			$el.append(html);
		}

		function sweepOut($el, windowWidth) {
			var dfr = $.Deferred(),
				pos = $el.position(),
				width = $el.width(),
				delta, final,
				options = $el.data("tlrkAnimOptions");

			windowWidth = windowWidth || $(window).width(); // check if the windowWidth is passed, if not - get it

			delta = windowWidth - pos.left;
			final = -(delta);

			setTimeout(function(){
				$el.animate({left: final, opacity: "toggle"}, options.speed, options.easing, function(){
					dfr.resolve();
				});
			}, options.delay);

			return dfr.promise();
		}

		function sweepIn($el, windowWidth, frameLeft) {
			var dfr = $.Deferred(),
				options = $el.data("tlrkAnimOptions"),
				positionData = $el.data("tlrkOriginalPos"),
				final = positionData.position.left,
				rightEdge;

			windowWidth = windowWidth || $(window).width(); // check if the windowWidth is passed, if not - get it

			$el.css({opacity: 0, display: "block"}); // move it outside the right edge of the screen
			$el.css("left", function(current){
				return current + windowWidth - frameLeft;
			});

			setTimeout(function(){
				$el.animate({left: final, opacity: 1}, options.speed, options.easing, function(){
					dfr.resolve();
				});
			}, options.delay);

			return dfr.promise();
		}


		// two pass function that first iterates all the elements and gets their position/width/height
		// and then sets their position to absolute
		function absolutize($elements) {

			// todo - move it to separate function and do it just once
			// gather the original position/dimension data for all elements
			$elements.each(function(){
				var $t = $(this);

				if ($t.data("tlrkOriginalPos")) return

				$t.data("tlrkOriginalPos", {
					position: $t.position(),
					width: $t.width(),
					height: $t.height(),
					css_pos: $t.css("position"),
					css_left: $t.css("left"),
					css_top: $t.css("top"),
					css_width: $t.css("width") || "auto",
					css_height: $t.css("height") || "auto"
				});

			});

			// set the absolute position
			$elements.each(function(){
				var $t = $(this),
					opos = $t.data("tlrkOriginalPos");

				$t.css({
					position: "absolute",
					left: opos.position.left,
					top: opos.position.top,
					width: opos.width,
					height: opos.height
				});
			});
		}

		function restoreFrameElements($elements) {
			$elements.each(function(){
				var $t = $(this),
					opos = $t.data("tlrkOriginalPos");

				if (!opos) return

				$t.css({
					position: opos.css_pos,
					left: opos.css_left,
					top: opos.css_top,
					width: opos.css_width,
					height: opos.css_height
				});
			});

		}

		var TlrkSlider = function( elem, options ){
			this.elem = elem;
			this.$elem = $(elem);
			this.options = options;
		};

		// the plugin prototype
		TlrkSlider.prototype = {
			defaults: {


				defaultElementOptions: {
					speed: 1200,
					easing: "easeInOutBack",
					// interval before the element starts moving when the fadeIn/Out functions are called
					// it's a good idea to give different delays for the different elements
					// if all have the same delay they'll start moving all together
					delay: 100
				},

				// dispose elements are these that are not included in the elements object
				// but affect the document flow and will be fadedIn/Out
				disposeDelay: 100, // delay for the dispose elements
				disposeSpeed: 1000, // how quickly they'll fadeOut/In

				delayBetweenTransition: 1000, // time between starting fadeOut and fadeIn
				delayAnimation: 7000, // time between auto changing the current frame

				loop: true, // if true when clicking next on the last frame the slider jumps to the first one

				autoStart: true, // start the automatic looping through the frames on init

				framesSelector: "section", // selector for the frames inside the slider

				elements: {
					"p": {delay: 100, speed: 1000, easing: "easeInOutBack"}
				},

				navigation: true, // the dots navigation on the bottom
				navigationClass: "slider-nav",

				// callbacks
				// another way to "catch" these events is with
				// $(-slider-element-).bind("animationStart")
				animationStart: null,
				animationEnd: null
			},

			init: function() {
				var c, e, element, $element,
					that = this,
					$firstFrame;

				c = this.config = $.extend({}, this.defaults, this.options);

				this.elem.style.position = "relative"; // make the wrapping element relative

				// basics
				this.$frames = this.$elem.find(c.framesSelector);
				this.framesCount = this.$frames.length;
				this.currentFrame = 0;
				this.queue = [];

				this._$elementsByFrame = {};
				this._$disposeElementsByFrame = {};

				for (i = 0; i < this.framesCount; i++) {
					this._$elementsByFrame[i] = this._getFrameElements(i); // cache the $elements by frame
					this._$disposeElementsByFrame[i] = this._getDisposeFrameElements(i); // cache the rest of the tree for each frame
				}

				if (c.navigation) {
					generateNavigation(this.$elem, this.framesCount, c);
					this.$navigation = this.$elem.find("."+c.navigationClass);
				}

				// bindings
				this.$elem.find(".slider-nav").delegate("a", "click", function(e){
					var frame = this.getAttribute("href").split("#")[1];
					that.go.call(that, frame);
					return false;
				});

				this.$elem // internal bindings for the callbacks
					.bind("animationStart", function(){
						if ($.isFunction(c.animationStart)) {c.animationStart.apply(that, arguments);}
					})
					.bind("animationEnd", function(){
						if ($.isFunction(c.animationEnd)) {c.animationEnd.apply(that, arguments);}
					})
				;

				// start animation?
				if (c.autoStart) {
					this.start();
				} else {
					this.running = false;
				}

				return this;
			},

			start: function(instant) {
				var that = this;

				if (this.timer) { // we'll clear the current timer
					window.clearTimeout(this.timer);
				}

				this.running = true;

				if (instant) {
					that.nextFrame();
				} else {
					this.timer = window.setTimeout(function(){ that.nextFrame.call(that) }, that.config.delayAnimation);
				}
			},

			stop: function() {
				if (!this.running) return; // we are not running

				this.running = false;
				window.clearTimeout(this.timer);
			},

			// main function for changing frames
			selectFrame: function(frame, dfr) {
				var c = this.config, // shorthand for the config
					that = this,
					dfr = dfr || $.Deferred(),
					dFadeIn = $.Deferred(),
					dFadeOut = $.Deferred();

				if (isNaN(frame) || frame < 0 || frame > this.framesCount || frame === this.currentFrame) {
					dfr.reject();
					return dfr.promise();
				}

				// clear the animation loop interval if the animation is running
				if (this.running && this.timer) {
					window.clearTimeout(this.timer);
				}

				// check if we are currenly running an animation.
				if (this.animated && this.queue.length > 0) {
					// wait for the last item in the queue to finish
					this.queue[this.queue.length-1].done(function(){
						that.selectFrame(frame, dfr); // and call again the selectFrame
					})
					return dfr.promise();
				}

				this.animated = true;
				this.$elem.trigger("animationStart", [this, frame]);

				this.queue.push(dfr);

				// fade the frames
				dFadeOut = this._fadeOutFrame(this.currentFrame);

				// hide the fadetout frame
				dFadeOut.done(function(){
					that.$frames.eq(that.currentFrame).hide();
				});

				window.setTimeout(function(){ // then wait delayBetweenTransition and fadeIn the new frame
					dFadeIn = that._fadeInFrame.call(that, frame).done(function(){
						// when both the fadeIn and fadeOut are done we'll resolve the selectFrame promise
						$.when(dFadeOut, dFadeIn).done(function(){
							that.animated = false;
							that.queue.shift();
							that.$elem.trigger("animationEnd", [that]);
							that.currentFrame = frame;
							dfr.resolve();
						});
					});
				}, c.delayBetweenTransition);

				// navigation html change
				if (this.config.navigation) {
					this.$navigation.find(".selected").removeClass("selected").end()
						.find("a").eq(frame).addClass("selected");
				}

				dfr.done(function(){ // we'll resume the loop animation after the transitions are done
					if (that.running) {
						that.start();
					}
				});

				return dfr.promise();
			},

			_fadeFrame: function(frame, callback, direction) {
				var dfr = $.Deferred(),
					$frame = this.$frames.eq(frame),
					$elements = this._$elementsByFrame[frame],
					windowWidth = $(window).width(), // cache it before the animations, so we don't have to check it for each element
					i, len,
					that = this,
					elementAnimations = [],
					$disposeElements = this._$disposeElementsByFrame[frame],
					$affectedElements,
					frameLeft = $frame.offset().left;

				direction = direction || "out";

				if (!$.isFunction(callback)) return; // do nothing if there's no callback passed

				$affectedElements = $elements.add($disposeElements);

				// position absolute the animation and dispose elements
				absolutize($affectedElements);

				// toggle the dispose elements
				if ($disposeElements.length > 0) {
					window.setTimeout(function(){
						$disposeElements[direction === "out" ? "fadeOut" : "fadeIn"](that.config.disposeSpeed);
					}, this.config.disposeDelay);
				}

				// invoke the callback for each element
				// the callback must return a promise
				$elements.each(function(){
					elementAnimations.push( callback.call(that, $(this), windowWidth, frameLeft) );
				});

				// wait for all the elements to finish their animation
				$.when.apply(this, elementAnimations).done(function(){
					//restoreFrameElements($affectedElements); // and restore the elements' position
					dfr.resolve(); // resolve the fade function
				});

				return dfr.promise();
			},

			_fadeOutFrame: function(frame) {
				var dfr = $.Deferred(),
					$frame = this.$frames.eq(frame),
					$disposeElements = this._$disposeElementsByFrame[frame];

				this._fadeFrame(frame, this._animationOut, "out").done(function(){
					dfr.resolve();
				})

				return dfr.promise();
			},

			_fadeInFrame: function(frame) {
				var dfr = $.Deferred(),
					$frame = this.$frames.eq(frame),
					$elements = this._$elementsByFrame[frame];

				this._restoreFrame(frame);

				$frame.show();

				this._fadeFrame(frame, this._animationIn, "in").done(function(){
					dfr.resolve();
				});

				return dfr.promise();
			},

			_restoreFrame: function(frame){
				if (!frame) return
				restoreFrameElements( this._$elementsByFrame[frame].add(this._$disposeElementsByFrame[frame]) );
			},

			nextFrame: function() {
				var frame = this.currentFrame+1,
					dfr = $.Deferred();

				if (frame > this.framesCount-1) {
					if (this.config.loop) {
						frame = 0;
					} else {
						dfr.reject();
					}
				};

				this.selectFrame(frame).done(function(){
					dfr.resolve();
				});

				return dfr.promise();
			},

			prevFrame: function() {
				var frame = this.currentFrame-1,
					dfr = $.Deferred();

				if (frame < 0) {
					if (this.config.loop) {
						frame = this.framesCount-1;
					} else {
						dfr.reject();
						return dfr.promise();
					}
				}

				this.selectFrame(frame).done(function(){
					dfr.resolve();
				});

				return dfr.promise();
			},

			go: function(str) { // shorthand
				switch (str) {
					case "next":
					case "+1":
						this.nextFrame();
						break;

					case "prev":
					case "-1":
						this.prevFrame();
						break;

					case "first":
						this.selectFrame(0);
						break;

					case "last":
						this.selectFrame(this.framesCount-1);
						break;

					default:
						if (isNaN(str)) return;
						this.selectFrame(Number(str));
				}
			},

			// returns jquery collection of animation elements
			_getFrameElements: function(frame) {
				var $frame = this.$frames.eq(frame),
					elements = this.config.elements,
					e, elementOptions,
					$found, $frameElements = $([]);

				for (e in elements) {
					elementOptions = elements[e];
					$found = $frame.find(e);
					$found.addClass("t-frame-element").data("tlrkAnimOptions", $.extend({}, this.defaults.defaultElementOptions, elementOptions ));
					$frameElements = $frameElements.add($found);
				}

				return $frameElements;
			},

			// returns jquery collection of elements that have to be faded out
			// i.e. elements on the same level as the animation elements
			// that doesn't contain other animation elements
			_getDisposeFrameElements: function(frame) {
				var $disposeElements = $([]),
					$frame = this.$frames.eq(frame),
					$elements = this._$elementsByFrame[frame];

				$elements.each(function(){
					var $t = $(this),
						$siblings = $t.siblings().not(".t-frame-element");

					$siblings.each(function(){
						var $t = $(this);
						// check if the node is not already marked and doesn't contains other frame elements
						if (!$t.hasClass("t-frame-dispose") && $t.find(".t-frame-element").length === 0) {
							$t.addClass("t-frame-dispose");
							$disposeElements = $disposeElements.add($t);
						}
					});

				});
				return $disposeElements;
			},


			// expose the internal animationIn/Out functions that are called for each element in the frame
			// two arguments are passed - the $element which have to be animated and the window width
			_animationIn: sweepIn,
			_animationOut: sweepOut

		}

		TlrkSlider.defaults = TlrkSlider.prototype.defaults;

		$.fn.tlrkSlider = function(options) {
			var otherArgs = Array.prototype.slice.call(arguments, 1);

			return this.each(function() {
				var $el = $(this),
					pluginData = $el.data("tlrkSlider");

				if (!pluginData) { // check if the slider is already attached
					pluginData = new TlrkSlider(this, options).init();
					$el.data("tlrkSlider", pluginData);
					return;
				}

				//change the options or call a method
				if (typeof options === "string") {

					// setting / getting option(s)
					if (options === "option") {

						if (typeof otherArgs[0] === "string" && typeof otherArgs[1] !== "undefined") { // set an option value
							pluginData.config[otherArgs[0]] = otherArgs[1];
						}

						if (typeof otherArgs[0] === "object") { // extend the config with new options
							pluginData.config = $.extend(pluginData.config, otherArgs[0]);
						}

					} else { // call a method?
						try {
							pluginData[options].apply(pluginData, otherArgs);
						} catch(ex) {
							throw "Error calling a plugin method (" + ex + ")";
						}
					}
				}
			});
		};

		window.TlrkSlider = TlrkSlider;

	})( jQuery, window , document );
	return jQuery;
});